package ftdpc;

import ftdpc.bean.TaskAttribute;
import ftdpc.bean.TaskItem;
import ftdpc.properties.TaskConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.task.TaskSchedulerBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.scheduling.support.PeriodicTrigger;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 类描述:  任务调度业务处理
 *
 * @author 王雷
 * @version 1.0.0
 * @date 2022/9/10 0010 上午 11:50
 */
@Slf4j
public class TaskDispatchBusinessProcessing implements ApplicationRunner {

    /**
     * 属性描述：线程执行容器
     *
     * @date : 2022/9/10 0010 下午 4:34
     */
    private final Map<String, ScheduledFuture<?>> scheduledFutureMap = new ConcurrentHashMap<>(16);

    /**
     * 属性描述：任务属性配置
     *
     * @date : 2022/9/14 0014 下午 1:07
     */
    protected final Map<String, TaskAttribute> taskAttributeMap = new ConcurrentHashMap<>(16);

    /**
     * 属性描述：任务配置处理
     *
     * @date : 2021/1/19 0019 下午 4:42
     */
    protected final ITaskItemConfigManager iTaskItemConfigManager;

    /**
    * 属性说明: 任务配置
    * @date: 2023-08-22 23:25
    */
    protected final TaskConfig taskConfig;

//    /**
//     * 属性描述：调度任务处理逻辑
//     *
//     * @date : 2021/1/19 0019 下午 4:42
//     */
//    private final List<ITaskServerBusinessProcessing> iTaskServerBusinessProcessingList;

    /**
     * 属性描述：任务执行处理器
     *
     * @date : 2022/9/11 0011 下午 1:29
     */
    private TaskScheduler taskScheduler;

    /**
     * 属性描述：上下文配置
     *
     * @date : 2022/9/10 0010 下午 4:32
     */
    private final ApplicationContext applicationContext;

    /**
     * 功能描述：任务调度业务处理
     *
     * @date : 2022/9/10 0010 下午 5:16
     */
    protected TaskDispatchBusinessProcessing(ITaskItemConfigManager iTaskItemConfigManager, TaskConfig taskConfig
            , ApplicationContext applicationContext) {
        this.iTaskItemConfigManager = iTaskItemConfigManager;
        this.taskConfig = taskConfig;
        this.applicationContext = applicationContext;
    }

    @Override
    public final void run(ApplicationArguments args) {
        log.debug("任务调度启动");
        doManager();
//        scheduledThreadPoolExecutor.scheduleWithFixedDelay(this::doManager, 1, 5, TimeUnit.SECONDS);
//        this.taskConfig();
//        taskConfig();
    }

    /**
     * 功能描述：业务执行
     * <br />
     * 启动时加载
     *
     * @date : 2022/9/10 0010 下午 9:31
     */
    private void doManager() {
        try {
            taskConfig();
        } catch (Exception e) {
            log.error("任务配置逻辑异常", e);
            return;
        }
        if (taskScheduler == null && !taskAttributeMap.isEmpty()) {
            //初始化线程池
            initTaskScheduler();
        }
        if (taskAttributeMap.isEmpty()) {
            clearTask();
            return;
        }
        for (String taskKey : taskAttributeMap.keySet()) {
            if (taskAttributeMap.get(taskKey).getTaskIsAutoRun()) {
                startTask(taskKey);
            }
        }
    }

    /**
     * 功能描述：初始线程池
     *
     * @date : 2022/9/14 0014 下午 4:49
     */
    protected void initTaskScheduler() {
        /*ThreadPoolTaskScheduler taskScheduler = new TaskSchedulerBuilder()
                .poolSize(taskAttributeMap.size()).threadNamePrefix("Task-Business-Processing").build();*/
        ThreadPoolTaskScheduler taskScheduler = new TaskSchedulerBuilder()
//                .poolSize(20).threadNamePrefix("Task-Business-Processing").build();
                .poolSize(taskConfig.getPoolSize()).threadNamePrefix(taskConfig.getNamePrefix()).build();
        //是否将取消后的任务从队列删除
//        taskScheduler.setRemoveOnCancelPolicy(true);
        taskScheduler.setRemoveOnCancelPolicy(taskConfig.getRemoveOnCancelPolicy());
//        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        taskScheduler.setWaitForTasksToCompleteOnShutdown(taskConfig.getWaitForTasksToCompleteOnShutdown());
        taskScheduler.initialize();
        this.taskScheduler = taskScheduler;
    }

    /**
     * 功能描述：获取有效的任务集合
     * @date : 2022/9/16 0016 下午 1:40
     */
    protected List<TaskItem> giveValidList(){
        return iTaskItemConfigManager.giveValidList();
    }

    /**
     * 功能描述：获取任务配置
     *
     * @date : 2022/9/12 0012 下午 3:06
     */
    protected void taskConfig() {
        final List<TaskItem> taskItems = giveValidList();
        final Map<String, String> beanNameTaskAttribute = new HashMap<>(16);
        // 记录数据集中的对象
        if (taskItems != null && !taskItems.isEmpty()) {
            taskItems.forEach(taskItem -> {
                if (taskAttributeMap.get(taskItem.getTaskKey()) == null) {
                    final TaskAttribute taskAttribute = new TaskAttribute().putByTaskItem(taskItem);
                    taskAttributeMap.put(taskItem.getTaskKey(), taskAttribute);
                    beanNameTaskAttribute.put(taskAttribute.getTaskExecutionTarget(), taskAttribute.getTaskKey());
                }
            });
        }
        // 记载当前系统已经存在的
        final List<String> beanNameList = new ArrayList<>(Arrays.asList(applicationContext
                .getBeanNamesForType(ITaskServerBusinessProcessing.class)));
        if (!beanNameList.isEmpty()) {
            for (String beanName : beanNameList) {
                if (beanNameTaskAttribute.get(beanName) == null) {
                    final TaskAttribute taskAttribute = new TaskAttribute().setTaskIsAutoRun(Boolean.FALSE)
                            .setTaskIsConfig(Boolean.FALSE).setExecuteErrorNum(0L).setTaskKey(giveUuid())
                            .setTaskName(applicationContext.getBean(beanName, ITaskServerBusinessProcessing.class)
                                    .giveTaskName()).setMaxExecuteNumSize(0L)
                            .setExecuteNum(0L).setExecutionCycleByInterval(1L)
                            .setExecutionCycleByIntervalUnit(TimeUnit.SECONDS).setTaskIsItEffective(0)
                            .setTaskExecutionTarget(beanName).setTaskIsConfig(Boolean.FALSE).setTaskIsAutoRun(Boolean.FALSE)
                            .setTaskDoesTheLogicExist(Boolean.TRUE);
                    taskAttributeMap.put(taskAttribute.getTaskKey(), taskAttribute);
                } else {
                    taskAttributeMap.get(beanNameTaskAttribute.get(beanName)).setTaskDoesTheLogicExist(Boolean.TRUE);
                }
            }
        } else {
            taskAttributeMap.forEach((taskKey, taskAttribute) -> taskAttribute.setTaskIsItEffective(0)
                    .setTaskDoesTheLogicExist(Boolean.FALSE));
        }
        /*if (iTaskServerBusinessProcessingList != null && !iTaskServerBusinessProcessingList.isEmpty()) {
            for (ITaskServerBusinessProcessing iTaskServerBusinessProcessing : iTaskServerBusinessProcessingList) {
                final String beanName = toLowerCaseFirstOne(iTaskServerBusinessProcessing.getClass().getSimpleName());
                if (beanNameTaskAttribute.get(beanName) == null) {
                    final TaskAttribute taskAttribute = new TaskAttribute().setTaskIsAutoRun(Boolean.FALSE)
                            .setTaskIsConfig(Boolean.FALSE).setExecuteErrorNum(0L).setTaskKey(giveUuid())
                            .setTaskName(iTaskServerBusinessProcessing.giveTaskName()).setMaxExecuteNumSize(0L)
                            .setExecuteNum(0L).setExecutionCycleByInterval(1L)
                            .setExecutionCycleByIntervalUnit(TimeUnit.SECONDS).setTaskIsItEffective(0)
                            .setTaskExecutionTarget(beanName).setTaskIsConfig(Boolean.FALSE).setTaskIsAutoRun(Boolean.FALSE)
                            .setTaskDoesTheLogicExist(Boolean.TRUE);
                    taskAttributeMap.put(taskAttribute.getTaskKey(), taskAttribute);
                } else {
                    taskAttributeMap.get(beanNameTaskAttribute.get(beanName))
                            .setTaskDoesTheLogicExist(Boolean.TRUE).setTaskIsItEffective(1);
                }
            }
        } else {
            taskAttributeMap.forEach((taskKey, taskAttribute) -> taskAttribute.setTaskIsItEffective(0)
                    .setTaskDoesTheLogicExist(Boolean.FALSE));
        }*/
    }

    /**
     * 生成不重复的uuid
     */
    protected String giveUuid() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 首字母转小写
     *
     * @param s 需要转换的字符串
     * @return 转换后的结果
     * @author 王雷    (2018年5月22日 下午6:50:15)
     */
    private String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return Character.toLowerCase(s.charAt(0)) + s.substring(1);
        }
    }

    /**
     * 获取任务日志信息
     *
     * @param taskKey 配置标识
     * @return 日志信息
     * @author 王雷    (2018年5月22日 下午6:50:15)
     */
    public String giveTaskLog(String taskKey) {
        return iTaskItemConfigManager.giveTaskLog(taskKey);
    }

    private final ReentrantLock lock = new ReentrantLock();

    /**
     * 功能描述：启动线程
     *
     * @param taskKey 任务标识
     * @date : 2022/9/10 0010 下午 8:41
     */
    protected void startTask(String taskKey) {
        lock.lock();
        try {
            final TaskAttribute taskAttribute = taskAttributeMap.get(taskKey);
            if (taskAttribute != null && taskAttribute.getTaskIsItEffective() == 0) {
                final ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(taskKey);
                if (scheduledFuture != null) {
                    log.error("线程：{}；已经存在，请先关闭", taskKey);
                    taskAttribute.setTaskExecutionMessage("已经存在，请先关闭");
                    return;
                }
                if (taskScheduler == null) {
                    log.error("没有有效的线程池处理对象");
                    taskAttribute.setTaskExecutionMessage("没有有效的线程池处理对象");
                    return;
                }
                Trigger trigger;
                try {
                    if (taskAttribute.getExecutionCycleByCron() != null && !"".equals(taskAttribute.getExecutionCycleByCron())) {
                        trigger = new CronTrigger(taskAttribute.getExecutionCycleByCron());
                    } else {
                        taskAttribute.setExecutionCycleByIntervalUnit(
                                taskAttribute.getExecutionCycleByIntervalUnit() == null ? TimeUnit.SECONDS
                                        : taskAttribute.getExecutionCycleByIntervalUnit());
                        trigger = new PeriodicTrigger(taskAttribute.getExecutionCycleByInterval()
                                , taskAttribute.getExecutionCycleByIntervalUnit());
                    }
                } catch (Exception e) {
                    log.error("任务：{}；初始化Trigger对象异常", taskAttribute, e);
                    taskAttribute.setTaskExecutionMessage("初始化Trigger对象异常");
                    return;
                }

                try {
                    //执行逻辑处理对象
                    final ITaskServerBusinessProcessing bean = applicationContext.getBean(taskAttribute.getTaskExecutionTarget()
                            , ITaskServerBusinessProcessing.class);
                    taskAttribute.setStartTime(new Date());
                    // 清空日志
                    iTaskItemConfigManager.putTaskLogClear(taskAttribute.getTaskKey());
                    scheduledFutureMap.put(taskAttribute.getTaskKey(), taskScheduler.schedule(() -> {
                        log.info("任务：{}——{}；定时任务执行，执行目标：{}", taskAttribute.getTaskName(), taskAttribute.getTaskKey()
                                , taskAttribute.getTaskExecutionTarget());
                        try {
                            //执行逻辑处理
                            bean.dispatchBusinessProcessing();
                        } catch (Exception e) {
                            log.error("任务：{}——{}；业务执行异常", taskAttribute.getTaskName(), taskAttribute.getTaskKey(), e);
                            taskAttribute.setExecuteErrorNum((taskAttribute.getExecuteErrorNum() == null ? 0L
                                    : taskAttribute.getExecuteErrorNum()) + 1).setTaskExecutionMessage("业务执行异常");
                            // 存储日志
                            iTaskItemConfigManager.putTaskErrorLog(taskAttribute.getTaskKey(), e);
                            return;
                        }
                        log.info("任务：{}——{}；执行结束", taskAttribute.getTaskName(), taskAttribute.getTaskKey());
                        /*final long lengthNum = taskAttribute.getExecuteNum() == null ? 0L : taskAttribute.getExecuteNum();
                        taskAttribute.setExecuteNum(lengthNum + 1).setTaskIsItEffective(1);*/
                    }, trigger));
                } catch (Exception e) {
                    taskAttribute.setTaskExecutionMessage("添加到线程出现异常");
                    taskAttribute.setStartTime(null);
                    log.error("任务：{}；添加到线程出现异常", taskAttribute, e);
                    return;
                }
                taskAttribute.setTaskExecutionMessage("线程装载完成").setTaskIsItEffective(1);
            } else {
                log.error("任务：{}；没有对应的处理属性配置或者配置被禁用", taskKey);
            }
        } catch (Exception e) {
            log.error("任务线程配置处理异常", e);
            throw e;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 功能描述：清空任务
     *
     * @date : 2022/9/11 0011 下午 1:58
     */
    protected void clearTask() {
        for (String taskKey : scheduledFutureMap.keySet()) {
            removeTask(taskKey);
        }
    }

    /**
     * 功能描述：移除任务
     *
     * @param taskKey 任务标识
     * @date : 2022/9/11 0011 下午 1:58
     */
    protected void removeTask(String taskKey) {
        final ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(taskKey);
        if (scheduledFuture == null) {
            log.error("任务：{}；不存在", taskKey);
            return;
        }
        scheduledFuture.cancel(true);
        log.error("任务：{}；终止结果：{}", taskKey, scheduledFuture.isCancelled());
        scheduledFutureMap.remove(taskKey);
        taskAttributeMap.get(taskKey).setTaskIsItEffective(0).setTaskExecutionMessage("线程关闭").setStartTime(null);
        //移除存储
//        scheduledFutureMap.remove(taskKey);
    }

    /*public TaskAttribute start() {
        ScheduledFuture<?> scheduledFuture = threadPoolTaskScheduler.schedule(() -> {
            log.error("定时任务执行");
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(1/0);
            log.error("等待结束");
        }, new CronTrigger("0/10 * * * * ?")*//* {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                return new CronTrigger("0/10 * * * * ?").nextExecutionTime(triggerContext);
            }
        }*//*);
        log.error("对象：{}, Class：{}", scheduledFuture, scheduledFuture.getClass().getTypeParameters());
        return null;
    }*/
}
